package com.example.medispider.service.pipeline;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.example.medispider.pojo.detail.detail.SettlementDetail;
import com.example.medispider.pojo.detail.userinfo.BriefUserInfo;
import com.example.medispider.pojo.master.SettlementMaster;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;

public class ExcelPipeline<T> implements Pipeline {
    private final Class<T> clazz;     //处理有效数据的类型
    private final ReentrantLock lock = new ReentrantLock();         // 线程安全锁（用于有效数据）
    private final ReentrantLock errorLock = new ReentrantLock();    // 线程安全锁（用于错误数据）
    private final String outputFilePath;       //输出文件路径（有效数据）
    private final String errorFilePath;        //输出文件路径（错误数据）
    private ExcelWriter excelWriter;
    private ExcelWriter errorExcelWriter;
    private WriteSheet writeSheet;
    private WriteSheet errorWriteSheet;
    private boolean firstWrite = true;        // 是否首次写入（有效数据）
    private boolean errorFirstWrite = true;   // 是否首次写入（错误数据）
    private long count = 0;                   // 数据总量（有效数据）
    private long errorCount = 0;              // 数据总量（错误数据）


    public ExcelPipeline(String outputFilePath, Class<T> clazz) {
        this(outputFilePath, null, clazz);
    }

    public ExcelPipeline(String outputFilePath, String errorFilePath, Class<T> clazz) {
        this.outputFilePath = Objects.requireNonNull(outputFilePath, "outputFilePath cannot be null");
        this.errorFilePath = errorFilePath;  // 允许为null
        this.clazz = Objects.requireNonNull(clazz, "clazz cannot be null");
    }


    @Override
    public void process(ResultItems resultItems, Task task) {
        List<T> data = getData(resultItems);
        if (data != null) {
            saveData(data);
        }
        // 处理明细中的错误数据（空数据）
        if (this.clazz == SettlementDetail.class) {
            BriefUserInfo briefUserInfo = getEmptyDetail(resultItems);
            if (briefUserInfo != null) {
                saveError(briefUserInfo);
            }
        }
    }

    /**
     * 保存有效数据
     *
     * @param data 数据集合
     */
    private void saveData(List<T> data) {
        lock.lock();
        try {
            if (!data.isEmpty()) {
                if (firstWrite) {
                    //首次写入
                    excelWriter = EasyExcel.write(outputFilePath, clazz).excelType(ExcelTypeEnum.CSV).charset(StandardCharsets.UTF_8).build();
                    writeSheet = EasyExcel.writerSheet().build();  // 无sheetName，因为csv格式的sheet名称为文件名
                    firstWrite = false;
                }
                excelWriter.write(data, writeSheet);
                count = count + data.size();
                System.out.println("成功写入" + data.size() + "条数据：" + this.clazz.getSimpleName());
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * 保存错误缓存集合中的数据
     *
     * @param briefUserInfo 单条错误数据
     */
    private void saveError(BriefUserInfo briefUserInfo) {
        errorLock.lock();
        try {
            if (errorFirstWrite) {
                //首次写入
                errorExcelWriter = EasyExcel.write(errorFilePath, BriefUserInfo.class).excelType(ExcelTypeEnum.CSV).charset(StandardCharsets.UTF_8).build();
                errorWriteSheet = EasyExcel.writerSheet().build();  // 无sheetName，因为csv格式的sheet名称为文件名
                errorFirstWrite = false;
            }
            errorExcelWriter.write(List.of(briefUserInfo), errorWriteSheet);
            errorCount++;
            System.out.println("成功写入1条错误数据");
        } finally {
            errorLock.unlock();
        }
    }

    /**
     * 安全获取有效数据
     */
    private List<T> getData(ResultItems resultItems) {
        String key = getKeyForClass();
        Object obj = resultItems.get(key);
        if (obj instanceof List<?> rawList && !rawList.isEmpty()) {
            // 检查元素类型
            if (this.clazz.isInstance(rawList.getFirst())) {
                @SuppressWarnings("unchecked")
                List<T> result = (List<T>) rawList;
                return result;
            } else {
                System.err.println("Warning: " + key + " contains elements of wrong type");
            }
        }
        return null;
    }

    /**
     * 获取错误信息（未查到明细的人员简要信息）
     *
     * @param resultItems ResultItems
     * @return BriefUserInfo
     */
    private BriefUserInfo getEmptyDetail(ResultItems resultItems) {
        Object emptyDetail = resultItems.get("emptyDetail");
        if (emptyDetail instanceof BriefUserInfo) {
            return (BriefUserInfo) emptyDetail;
        }
        return null;
    }

    /**
     * 根据当前处理数据的类型 <T> 查找key
     *
     * @return key
     */
    private String getKeyForClass() {
        if (this.clazz == SettlementDetail.class) {
            return "details";
        } else if (this.clazz == SettlementMaster.class) {
            return "masters";
        }
        throw new IllegalArgumentException("Unsupported class: " + this.clazz.getName());
    }

    /**
     * 关闭Pipeline时手动调用，最后一次保存缓存数据、释放资源、还原参数等
     * 仅手动调用一次，线程安全
     */
    public void close() {
        try {
            if (excelWriter != null) {
                excelWriter.finish();
            }
            System.out.println("累计写入" + count + "条数据：" + this.clazz.getSimpleName());
            if (errorExcelWriter != null) {
                errorExcelWriter.finish();
            }
            System.out.println("累计写入" + errorCount + "条错误数据");
        } catch (Exception e) {
            System.err.println("关闭ExcelWriter时发生错误: " + e.getMessage());
        }
    }
}
